package org.xp.judgeplatform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.xp.judgeplatform.common.PageResult;
import org.xp.judgeplatform.converter.ProblemConverter;
import org.xp.judgeplatform.exception.BusinessException;
import org.xp.judgeplatform.mapper.ProblemMapper;
import org.xp.judgeplatform.pojo.dto.ProblemDTO.ProblemCreateDTO;
import org.xp.judgeplatform.pojo.dto.ProblemDTO.ProblemQueryDTO;
import org.xp.judgeplatform.pojo.dto.ProblemDTO.ProblemUpdateDTO;
import org.xp.judgeplatform.pojo.entity.Problem;
import org.xp.judgeplatform.pojo.vo.ProblemVO.ProblemVO;
import org.xp.judgeplatform.service.ProblemService;

import java.util.List;

@Service
@Slf4j
@AllArgsConstructor
public class ProblemServiceImpl implements ProblemService {

    private final ProblemMapper problemMapper;
    private final ProblemConverter problemConverter;



    @Override
    public ProblemVO getProblemById(Long id) {

        if (id == null || id <= 0) {
            throw new BusinessException(400, "题目ID无效");
        }

        try {
            Problem problem = problemMapper.selectById(id);
            if (problem == null) {
                throw new BusinessException(404, "题目不存在");
            }

            ProblemVO vo;
            try {
                vo = problemConverter.toProblemVO(problem);
            } catch (Exception e) {
                log.error("题目数据转换失败, id={}", id, e);
                throw new BusinessException(500, "题目数据格式错误");
            }

            try {
                computedPassRate(vo);
            } catch (Exception e) {
                log.warn("计算通过率失败, id={}", id, e);
                vo.setAcceptanceRate(0.0);
            }

            vo.setAuthorName("出题者");
            return vo;

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询题目失败, id={}", id, e);
            throw new BusinessException(500, "查询题目失败，请稍后重试");
        }
    }
    
    @Override
    public PageResult<ProblemVO> getProblemsForUser(ProblemQueryDTO problemQueryDTO) {
        QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();

        // 用户只能查看已发布的公开题目
        queryWrapper.like(StringUtils.hasText(problemQueryDTO.getTitle()), "title", problemQueryDTO.getTitle())
                .eq(StringUtils.hasText(problemQueryDTO.getDifficulty()), "difficulty", problemQueryDTO.getDifficulty())
                .eq(StringUtils.hasText(problemQueryDTO.getCategory()), "category", problemQueryDTO.getCategory())
                .eq("status", "已发布")
                .eq("is_public", true);

        // 设置分页
        Page<Problem> page = new Page<>(problemQueryDTO.getPageNum(), problemQueryDTO.getPageSize());

        // 查询
        Page<Problem> problemPage = problemMapper.selectPage(page, queryWrapper);

        // 转换为VO
        List<ProblemVO> problemVOList = problemConverter.toProblemVOList(problemPage.getRecords());

        // 处理额外字段
        problemVOList.forEach(this::computedPassRate);

        return PageResult.of(problemVOList, problemPage.getTotal(),
                (int)problemPage.getCurrent(),
                (int)problemPage.getSize());
    }
    
    @Override
    public PageResult<ProblemVO> getProblemsForPublic(ProblemQueryDTO problemQueryDTO) {
        // 公开接口和用户接口的逻辑目前相同，都只显示已发布的公开题目
        return getProblemsForUser(problemQueryDTO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProblemVO createProblem(ProblemCreateDTO createDTO, Integer userId) {
        if (createDTO == null) {
            throw new BusinessException(400, "创建参数不能为空");
        }

        if (!StringUtils.hasText(createDTO.getTitle())) {
            throw new BusinessException(400, "题目标题不能为空");
        }

        if (userId == null || userId <= 0) {
            throw new BusinessException(400, "用户ID无效");
        }

        try {
            Problem problem = new Problem();
            BeanUtils.copyProperties(createDTO, problem);

            try {
                problem.setSlug(generateSlug(createDTO.getTitle()));
            } catch (Exception e) {
                log.error("生成slug失败, title={}", createDTO.getTitle(), e);
                throw new BusinessException(500, "生成题目标识失败");
            }

            problem.setAuthorId(userId);

            try {
                problemMapper.insert(problem);
            } catch (org.springframework.dao.DuplicateKeyException e) {
                // 处理唯一键冲突
                log.error("题目创建失败，标题或slug重复, title={}", createDTO.getTitle(), e);
                throw new BusinessException(400, "题目标题或标识已存在");
            } catch (Exception e) {
                log.error("题目创建失败, title={}", createDTO.getTitle(), e);
                throw new BusinessException(500, "题目创建失败，请稍后重试");
            }

            log.info("题目创建成功: id={}, title={}", problem.getId(), problem.getTitle());

            try {
                return problemConverter.toProblemVO(problem);
            } catch (Exception e) {
                log.error("题目数据转换失败, id={}", problem.getId(), e);
                throw new BusinessException(500, "题目创建成功但数据格式转换失败");
            }
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("题目创建过程发生未知异常", e);
            throw new BusinessException(500, "题目创建失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProblemVO updateProblem(Long id, ProblemUpdateDTO updateDTO) {
        Problem existingProblem = problemMapper.selectById(id);
        if (existingProblem == null) {
            throw new BusinessException(400, "题目不存在");
        }

        // 更新非空字段
        if(StringUtils.hasText(updateDTO.getTitle())){
            existingProblem.setTitle(updateDTO.getTitle());
            existingProblem.setSlug(generateSlug(updateDTO.getTitle()));
        }

        if (StringUtils.hasText(updateDTO.getDescription())) {
            existingProblem.setDescription(updateDTO.getDescription());
        }

        if (StringUtils.hasText(updateDTO.getDifficulty())) {
            existingProblem.setDifficulty(updateDTO.getDifficulty());
        }

        if (StringUtils.hasText(updateDTO.getCategory())) {
            existingProblem.setCategory(updateDTO.getCategory());
        }

        if (StringUtils.hasText(updateDTO.getInputDescription())) {
            existingProblem.setInputDescription(updateDTO.getInputDescription());
        }

        if (StringUtils.hasText(updateDTO.getOutputDescription())) {
            existingProblem.setOutputDescription(updateDTO.getOutputDescription());
        }

        if (StringUtils.hasText(updateDTO.getSampleInput())) {
            existingProblem.setSampleInput(updateDTO.getSampleInput());
        }

        if (StringUtils.hasText(updateDTO.getSampleOutput())) {
            existingProblem.setSampleOutput(updateDTO.getSampleOutput());
        }

        if (StringUtils.hasText(updateDTO.getHint())) {
            existingProblem.setHint(updateDTO.getHint());
        }

        if (updateDTO.getTimeLimit() != null) {
            existingProblem.setTimeLimit(updateDTO.getTimeLimit());
        }
        if (updateDTO.getMemoryLimit() != null) {
            existingProblem.setMemoryLimit(updateDTO.getMemoryLimit());
        }
        if (updateDTO.getTotalScore() != null) {
            existingProblem.setTotalScore(updateDTO.getTotalScore());
        }
        if (StringUtils.hasText(updateDTO.getStatus())) {
            existingProblem.setStatus(updateDTO.getStatus());
        }
        if (updateDTO.getIsPublic() != null) {
            existingProblem.setIsPublic(updateDTO.getIsPublic());
        }

        // 保存更新
        problemMapper.updateById(existingProblem);

        log.info("题目更新成功: id={}, title={}", id, existingProblem.getTitle());
        
        return problemConverter.toProblemVO(existingProblem);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProblem(Long id) {
        Problem problem = problemMapper.selectById(id);
        if (problem == null) {
            throw new BusinessException(404, "题目不存在");
        }
        
        // 物理删除（如果需要软删除，可以修改 status 为 "已删除"）
        problemMapper.deleteById(id);
        
        log.info("题目删除成功: id={}, title={}", id, problem.getTitle());
    }

    @Override
    public PageResult<ProblemVO> getProblemsForAdmin(ProblemQueryDTO problemQueryDTO) {
        QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
        
        // 管理员可以查看所有状态的题目（包括草稿、私有题目）
        queryWrapper.like(StringUtils.hasText(problemQueryDTO.getTitle()), "title", problemQueryDTO.getTitle())
                .eq(StringUtils.hasText(problemQueryDTO.getDifficulty()), "difficulty", problemQueryDTO.getDifficulty())
                .eq(StringUtils.hasText(problemQueryDTO.getCategory()), "category", problemQueryDTO.getCategory());
        
        // 按更新时间倒序
        queryWrapper.orderByDesc("updated_at");

        // 分页查询
        Page<Problem> page = new Page<>(problemQueryDTO.getPageNum(), problemQueryDTO.getPageSize());
        Page<Problem> problemPage = problemMapper.selectPage(page, queryWrapper);

        // 转换为VO
        List<ProblemVO> problemVOList = problemConverter.toProblemVOList(problemPage.getRecords());

        // 处理额外字段
        problemVOList.forEach(this::computedPassRate);

        return PageResult.of(problemVOList, problemPage.getTotal(),
                (int)problemPage.getCurrent(),
                (int)problemPage.getSize());
    }

    /**
     * 生成唯一的slug
     * 优化：限制循环次数，添加时间戳避免高并发冲突，限制长度
     */
    private String generateSlug(String title) {
        // 生成基础slug并限制长度
        String baseSlug = title.toLowerCase()
                .replaceAll("[^a-z0-9\\u4e00-\\u9fff]", "-")
                .replaceAll("-+", "-")
                .replaceAll("^-|-$", "");
        
        // 限制slug长度为100字符
        if (baseSlug.length() > 100) {
            baseSlug = baseSlug.substring(0, 100);
        }
        
        // 如果基础slug为空，使用默认值
        if (baseSlug.isEmpty()) {
            baseSlug = "problem";
        }
        
        // 检查slug是否已存在，限制最多尝试10次
        String finalSlug = baseSlug;
        int maxAttempts = 10;
        int counter = 1;
        
        while (counter <= maxAttempts && isSlugExists(finalSlug)) {
            finalSlug = baseSlug + "-" + counter;
            counter++;
        }
        
        // 如果10次尝试后仍然冲突，添加时间戳确保唯一性
        if (counter > maxAttempts && isSlugExists(finalSlug)) {
            finalSlug = baseSlug + "-" + System.currentTimeMillis();
            log.warn("Slug生成冲突次数过多，使用时间戳: {}", finalSlug);
        }
        
        return finalSlug;
    }
    
    /**
     * 检查slug是否已存在
     */
    private boolean isSlugExists(String slug) {
        QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("slug", slug);
        return problemMapper.selectCount(queryWrapper) > 0;
    }

    private void computedPassRate(ProblemVO problemVO) {
        if (problemVO.getSubmissionCount() != null && problemVO.getSubmissionCount() > 0) {
            double rate = (double) problemVO.getAcceptedCount() / problemVO.getSubmissionCount() * 100;
            problemVO.setAcceptanceRate(Math.round(rate * 100.0) / 100.0);
        } else {
            problemVO.setAcceptanceRate(0.0);
        }

        // 设置作者名称
        problemVO.setAuthorName("管理员");
    }
}
